/*
 * Copyright © 2009 Perseus Project - Tufts University <http://www.perseus.tufts.edu>
 *
 * This file is part of DbUtilPerseus.
 *
 * DbUtilPerseus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * DbUtilPerseus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with DbUtilPerseus.  If not, see <http://www.gnu.org/licenses/>.
 */

package eu.himeros.util;

import java.sql.*;

/**
 * Manage Db connections providing shortcuts for Statements, PreparedStatements and ResultSets.
 *
 * @author Federico Boschetti <federico.boschetti.73@gmail.com>
 */
public class DbManager{
    public Connection con;
    public Statement stmt;
    public PreparedStatement pstmt;
    public ResultSet rst;
    
    public Statement[] stmts;
    public PreparedStatement[] pstmts;
    public ResultSet[] rsts;

    private String driverName;
    private String dbName;
    
    private boolean dbArray;
    private int stmtsSize;
    private int pstmtsSize;
    private int rstsSize;
    
    /**
     * Initialize a generic DbManager.
     *
     * @param driver the driver.
     * @param database the database name.
     * @param login the login.
     * @param passwd the password.
     */
    public DbManager(String driver, String database, String login, String passwd){
	dbArray=false;
	try{
	    initDb(driver, database, login, passwd);
	    stmt=con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
	}catch(Exception e){
	    e.printStackTrace();
	}
    }

    /**
     * Initialize the DbManager, using hsqldb defaults.
     */
    public DbManager(){
	dbArray=false;
	try{
	    initDb("hsqldb", ".", "sa", "");
	    stmt=con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
           
	}catch(Exception e){
	    e.printStackTrace();
	}
    }

    /**
     * Initialize the DbManager.
     *
     * @param driver the driver.
     * @param database the database name.
     * @param login the login.
     * @param passwd the password.
     * @param stmtsSize the max number of Statement instances.
     * @param pstmtsSize the max number of PreparedStatement instances.
     * @param rstsSize the max number of ResultSet instances.
     */
    public void dbManager(String driver, String database, String login, String passwd, int stmtsSize, int pstmtsSize, int rstsSize){
	dbArray=true;
	this.stmtsSize=stmtsSize;
	this.pstmtsSize=pstmtsSize;
	this.rstsSize=rstsSize;
	try{
	    initDb(driver, database, login, passwd);
	    if(stmtsSize>0){
		stmts=new Statement[stmtsSize];
		for(int i=0;i<stmtsSize;i++){
		    stmts[i]=con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
		}
	    }
	    if(pstmtsSize>0){
		pstmts=new PreparedStatement[pstmtsSize];
	    }
	    if(rstsSize!=0){
		rsts=new ResultSet[rstsSize];
	    }
	}catch(Exception e){
	    e.printStackTrace();
	}
    }

    /**
     * Initialize the DbManager.
     *
     * @param driver the driver.
     * @param database the database name.
     * @param login the login.
     * @param passwd the password.
     * @param stmtsSize the max number of Statement instances.
     * @param pstmtsSize the max number of PreparedStatement instances.
     * @param rstsSize the max number of ResultSet instances.
     */
    public DbManager(String driver, String database, String login, String passwd, int stmtsSize, int pstmtsSize, int rstsSize){
	dbManager(driver, database, login, passwd, stmtsSize, pstmtsSize, rstsSize);
    }

    /**
     * Initialize the DbManager.
     *
     * @param driver the driver.
     * @param database the database name.
     * @param login the login.
     * @param passwd the password.
     * @param stmtsSize the max number of Statement instances.
     * @param rstsSize the max number of ResultSet instances.
     */
    public DbManager(String driver, String database, String login, String passwd, int stmtsSize, int rstsSize){
	dbManager(driver, database, login, passwd, stmtsSize, 0,  rstsSize);
    }
    
    /**
     * Provide the PreparedStatement, given a query.
     *
     * @param query the query.
     * @return the PreparedStatement based on the query.
     */
    public PreparedStatement prepareStatement(String query){
	try{
	    pstmt=con.prepareStatement(query,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
	    return pstmt;
	}catch(Exception e){
	    e.printStackTrace();
	    return null;
	}
    }

    /**
     * Shortcut for hsqldb driver name.
     *
     * @param driver the driver.
     * @param database the database name.
     */
    private void longNames(String driver, String database){
	if(driver.equals("hsqldb")){
	    driverName="org.hsqldb.jdbcDriver";
	    dbName="jdbc:hsqldb:"+database;
	}else{
	    driverName=driver;
	    dbName=database;
	}
    }

    /**
     * Initialize the database.
     *
     * @param driver the driver.
     * @param database the database name.
     * @param login the login.
     * @param passwd the password.
     */
    private void initDb(String driver, String database, String login, String passwd){
	try{
	    longNames(driver, database);
	    Class.forName(driverName);
	    con=DriverManager.getConnection(dbName, login, passwd);
	}catch(Exception e){
	    e.printStackTrace();
	}
    }

    /**
     * Close the single instance of ResultSet, PreparedStatement, Statement and Connection.
     */
    private void closeSingle(){
	try{
	    if(rst!=null){
		rst.close();
	    }
	    if(pstmt!=null){
		pstmt.close();
	    }
	    stmt.close();
	    con.close();
	}catch(Exception e){
	    e.printStackTrace();
	}
    }

    /**
     * Close the array.
     */
    private void closeArray(){
	try{
	    for(int i=0;i<rstsSize;i++){
		if(rsts[i]!=null){
		    rsts[i].close();
		}
	    }
	    for(int i=0;i<stmtsSize;i++){
		if(stmts[i]!=null){
		    stmts[i].close();
		}
	    }
	    for(int i=0;i<pstmtsSize;i++){
		if(pstmts[i]!=null){
		    pstmts[i].close();
		}
	    }
	    con.close();
	}catch(Exception e){
	    e.printStackTrace();
	}
    }

    /**
     * Close the array or the single instance.
     */
    public void close(){
	if(dbArray){
	    closeArray();
	}else{
	    closeSingle();
	}
    }

    /**
     *  Close the ResultSet
     * @param rst the ResultSet
     */
    public void close(ResultSet rst){
	try{
	    rst.close();
	    closeSingle();
	}catch(Exception e){
	    e.printStackTrace();
	}
    }

}
